//
//  HomeCell.swift
//  sinaDemo
//
//  Created by admin on 2021/3/7.
//
/**
 tableview的卡顿原因：
 VSync（垂直同步信号量）：当电子枪绘制完毕一帧后，电子枪会回到原位，发送一个VSync，然后从帧缓存里取下一帧的信息，帧缓存是由cpu进行计算然后给gpu进行渲染
 
 如果在一个 VSync 时间内，CPU 或者 GPU 没有完成内容提交到帧缓冲区，则那一帧就会被丢弃，等待下一次再显示，而这时显示屏会保留之前的内容不变，这就是掉帧，也就是卡顿的原因。
 
 优化tableview的方法
 （1）利用runloop，按需加载图片：即滑动过程中图片会被加入TaskMarr数组，并限制数组元素个数，监听runloop，停止滑动后再处理TaskMarr里的task（图片加载请求）。
 这样的结果就是滑动过程中的一些图片被放弃加载
 （2）利用tableview的按需加载方式。只加载目标行数前后3行的cell，其他cell就不会被加载。（这样做会更省性能，但是用户体验会稍差）
 （3）scrollViewWillBeginDecelerating（手指停止滑动，开始自动滑动时）就可以开始加载image或cell。
 */
import UIKit
import SDWebImage
private let itemMargin = CGFloat(8).auto()
private let edgeMargin = CGFloat(12).auto()
enum photoBrowserKey{
    case index
    case urls
    case smallImages
    case image
    case origanalFrame
    case cell
}
class HomeCell: UITableViewCell{
    var index:IndexPath?
    @IBOutlet weak var retextH: NSLayoutConstraint!
    @IBOutlet weak var mytextH: NSLayoutConstraint!
    @IBOutlet weak var zhuanfaBackImg: UIImageView!
    @IBOutlet weak var dianzan: UIButton!
    @IBOutlet weak var pinglun: UIButton!
    @IBOutlet weak var zhuanfa: UIButton!
    @IBOutlet weak var picConstraintH: NSLayoutConstraint!
    @IBOutlet weak var picConstraintW: NSLayoutConstraint!
    @IBOutlet weak var picCollectionView: UICollectionView!
    @IBOutlet weak var zhuanfaTop: NSLayoutConstraint!
    @IBOutlet weak var picBottom: NSLayoutConstraint!
    @IBOutlet weak var iconImg: UIImageView!
    @IBOutlet weak var screenName: UILabel!
    @IBOutlet weak var crateAt: UILabel!
    @IBOutlet weak var source: UILabel!
    @IBOutlet weak var myText: XMLabel!
    @IBOutlet weak var reteewText: XMLabel!
    @IBOutlet weak var bottomToolView: UIView!
    
    typealias runloopTask = (()->Void)
    var TaskMarr:[runloopTask] = [runloopTask]()
    let maxTasksNumber = 15//延迟加载图片，省流量和资源
    private var runLoopActivity: CFRunLoopActivity?
    @objc func run(){}
    var HomeViewModel:HomeModelTool?{
        didSet {
            guard let viewModel = HomeViewModel else {
                return
            }
            //设置头像
            self.iconImg.sd_setImage(with: URL.init(string: viewModel.homeModel?.user?.avatar_large ?? ""), completed: nil)
            //设置认证
            
            //设置昵称
            self.screenName.text =  viewModel.homeModel?.user?.screen_name ?? ""
            //设置时间
            self.crateAt.text = viewModel.creatAtText ?? ""
            //设置来源
            self.source.text = viewModel.courceText ?? ""
            //设置文字
            let textstr  = viewModel.homeModel?.text ?? ""
            let allTextStringRang = textstr.range(of: "...全文")
            if allTextStringRang != nil && textstr.count > 140 {
                let final  = textstr[textstr.startIndex ..< allTextStringRang!.upperBound]
                self.myText.text = String(final)
            }
            else{
                self.myText.text = textstr
            }
            self.myText.linkTapHandler = {(label,str,range) in
                print(str)
            }
            //设置底部工具栏的文字
            if viewModel.homeModel!.reposts_count ?? 0 > 0 {
                self.zhuanfa.setTitle("\(viewModel.homeModel!.reposts_count!)", for: .normal)
            }else{
                self.zhuanfa.setTitle("转发", for: .normal)
            }
            if viewModel.homeModel!.comments_count ?? 0 > 0 {
                self.pinglun.setTitle("\(viewModel.homeModel!.comments_count!)", for: .normal)
            }else{
                self.pinglun.setTitle("评论", for: .normal)
            }
            if viewModel.homeModel!.attitudes_count ?? 0 > 0 {
                self.dianzan.setTitle("\(viewModel.homeModel!.attitudes_count!)", for: .normal)
            }else{
                self.dianzan.setTitle("点赞", for: .normal)
            }
            //设置昵称文字颜色
            if viewModel.homeModel?.retweeted_status != nil {
                //有转发
                self.zhuanfaBackImg.isHidden = false
                
            }else{
                //没有转发内容
                self.zhuanfaBackImg.isHidden = true
                
            }
            //设置转发内容
            if let retext = viewModel.homeModel?.retweeted_status?.text {
                var textstr  = retext
                let allTextStringRang = textstr.range(of: "...全文")
                if allTextStringRang != nil && textstr.count > 140 {
                    textstr  = String(textstr[textstr.startIndex ..< allTextStringRang!.upperBound])
                }
                let retweeName = viewModel.homeModel?.retweeted_status?.user?.screen_name ?? ""
                if retweeName.count > 0 {
                    self.reteewText.text = "@\(retweeName): " +  textstr
                }
                zhuanfaTop.constant = 10
                
            }else{
                zhuanfaTop.constant = 0
                self.reteewText.text = ""
                //                retextH.constant = 0
            }
            //必须每次都要重新设置一下
            //设置正文高度
            mytextH.constant = self.myText.attributeHeight
            //设置转发文字高度
            retextH.constant = self.reteewText.attributeHeight
            
            let picCount =  viewModel.picUrls.count
            //计算pic的宽度和高度约束
            let PicViewSize = calculatePicViewSize(count:picCount)
            picConstraintH.constant =  PicViewSize.height
            picConstraintW.constant =  PicViewSize.width
            picCollectionView.reloadData()
            
            if viewModel.cellHeight == 0 {
                layoutIfNeeded()
                viewModel.cellHeight = bottomToolView.frame.maxY
//                viewModel.cellHeight = picCollectionView.bottom + picBottom.constant + bottomToolView.height
            }
        }
    }
    
    override func awakeFromNib() {
        super.awakeFromNib()
        self.iconImg.layer.masksToBounds = true
        self.iconImg.layer.cornerRadius = self.iconImg.frame.width/2
        
        picCollectionView.register(UINib.init(nibName: "ItemCell", bundle: Bundle.main), forCellWithReuseIdentifier: "ItemCellId")
        //        picCollectionView.register(ItemCell.self, forCellWithReuseIdentifier: "ItemCellId")
        picCollectionView.dataSource = self
        picCollectionView.delegate = self
        picCollectionView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
        //添加runloop观察者
        addRunloopObserver()
    }
    
    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)
        
        // Configure the view for the selected state
    }
    
}
extension HomeCell:UIScrollViewDelegate{
    private func calculatePicViewSize(count:Int)->CGSize{
        
        let layout = picCollectionView.collectionViewLayout as! UICollectionViewFlowLayout
        //没有配图
        if count == 0 {
            layout.itemSize = CGSize(width: 0.1, height: 0.1)
            picBottom.constant = 0
            return CGSize.zero
        }
        picBottom.constant = 10
        if count == 1 {
            let str = self.HomeViewModel!.picUrls.last!
            let image = SDImageCache.shared.imageFromDiskCache(forKey: str)
            if image != nil {
                let size =  CGSize.init(width: (image!.size.width) * 2, height: (image!.size.height) * 2)
                //布局picview
                layout.itemSize = size
                return size
            }
        }
        
        //布局picview
        let imageWH = (kScreenWidth - edgeMargin.floatValue * 2 -  itemMargin.floatValue * 2) / 3
        layout.itemSize = CGSize(width: imageWH, height: imageWH)
        layout.minimumLineSpacing = itemMargin.floatValue
        layout.minimumInteritemSpacing = itemMargin.floatValue
        
        //4个配图
        if count == 4{
            let picViewWH = imageWH * 2 + itemMargin.floatValue
            return CGSize(width: picViewWH, height: picViewWH)
        }
        
        let numberLine = ((count - 1)/3 + 1).floatValue
        let picViewH = imageWH * numberLine + itemMargin.floatValue * (numberLine - 1)
        let picViewW = kScreenWidth - 2 * edgeMargin.floatValue
        return CGSize(width: picViewW, height: picViewH)
    }
}
// MARK: - cell的图片collectionview的代理方法

extension HomeCell:UICollectionViewDataSource,UICollectionViewDelegate{
    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return self.HomeViewModel?.picUrls.count ?? 0
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell:ItemCell = collectionView.dequeueReusableCell(withReuseIdentifier: "ItemCellId", for: indexPath) as! ItemCell
        
        guard let ImageUrl = self.HomeViewModel?.picUrls[indexPath.row] else {
            return cell
        }
        if RunLoop.current.currentMode == RunLoop.Mode.tracking  {
            cell.backImg.image = nil
        }
        //runloop按需（15个） 延时加载图片
        addTasks {
            //其实sdwebimage已经是异步加载，避免了cell卡顿
            cell.backImg.sd_setImage(with: URL.init(string: ImageUrl), placeholderImage: UIImage.init(named: "compose_toolbar_picture"), options: []) { (image, error, SDImageCacheType, URL) in
            }
        }
        
        return cell
    }
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        //更换大图模式
        var picurls = [String]()
        let smallUrls = self.HomeViewModel?.picUrls ?? []
        for url in smallUrls {
            let lagerUrl = url.replacingOccurrences(of: "thumbnail", with: "large")
            picurls.append(lagerUrl)
        }
        guard let currentcell = collectionView.cellForItem(at: indexPath) as? ItemCell else{
            return
        }
        //当前cell相对于collectionView的位置转换成相对于kWindow的位置
        let oringalFrame =  collectionView.convert(currentcell.frame, to: kWindow)
        
        let userInfo = [photoBrowserKey.index:indexPath,photoBrowserKey.urls:picurls,photoBrowserKey.smallImages:smallUrls,photoBrowserKey.origanalFrame:oringalFrame,photoBrowserKey.cell:self] as [photoBrowserKey : Any]
        
        NotificationCenter.default.post(name: Notification.Name.init(PopPhotoBrowserCtrNotification), object: nil, userInfo: userInfo)
    }
    
}
// MARK: - 设置runloop监听，用来延时加载图片

extension HomeCell{
    func addTasks(_ Task:@escaping  runloopTask) {
        TaskMarr.append(Task)
        if TaskMarr.count > maxTasksNumber {
            TaskMarr.removeFirst()
        }
    }
    
    func addRunloopObserver() {
        //获取当前runloop(因为当前runloop是主线程的runloop)
        let currentRunloop = CFRunLoopGetCurrent()
        //runloop观察者上下文， 为下面创建观察者准备，只有创建上下文才能在回调了拿到self对象，才能进行我们的逻辑操作. 这是一个结构体。
        /**
         typedef struct {
         CFIndex    version;
         void *    info;
         const void *(*retain)(const void *info);
         void    (*release)(const void *info);
         CFStringRef    (*copyDescription)(const void *info);
         } CFRunLoopObserverContext;
         **/
        let info = Unmanaged<HomeCell>.passUnretained(self).toOpaque()
        var context:CFRunLoopObserverContext = CFRunLoopObserverContext.init(version: 0, info: info, retain: nil, release: nil, copyDescription: nil)
        //创建Runloop观察者  kCFRunLoopBeforeWaiting  观察在等待状态之前  runloop有下面几种状态 看英文应该知道了。
        /*
         kCFRunLoopEntry = (1UL << 0), // 进入RunLoop
         kCFRunLoopBeforeTimers = (1UL << 1), // 即将开始Timer处理
         kCFRunLoopBeforeSources = (1UL << 2), // 即将开始Source处理
         kCFRunLoopBeforeWaiting = (1UL << 5), // 即将进入休眠
         kCFRunLoopAfterWaiting = (1UL << 6), //从休眠状态唤醒
         kCFRunLoopExit = (1UL << 7), //退出RunLoop
         kCFRunLoopAllActivities = 0x0FFFFFFFU
         */
        let obserberRef:CFRunLoopObserver = CFRunLoopObserverCreate(kCFAllocatorDefault, CFRunLoopActivity.allActivities.rawValue, true, 0, runLoopCallBack(), &context)
        //给当前runloop的defaultMode模式下添加观察者
        CFRunLoopAddObserver(currentRunloop, obserberRef, CFRunLoopMode.defaultMode)
        //主页不需要移除观察者（一般deinit时候可以移除）
//        CFRunLoopRemoveObserver(currentRunloop, obserberRef, CFRunLoopMode.defaultMode)
    }
    
    func runLoopCallBack() -> CFRunLoopObserverCallBack {
        return { (observer, activity, context) -> Void in
            let weakSelf = Unmanaged<HomeCell>.fromOpaque(context!).takeUnretainedValue()
            weakSelf.runLoopActivity = activity
//            if activity == .afterWaiting{
//                print("afterWaiting")//唤醒
//            }
//            if activity == .beforeWaiting {
//                print("beforeWaiting")//将要进行睡眠了
//            }
            if (weakSelf.TaskMarr.count > 0) {
                //获取一次数组里面的任务并执行（sdweb展示图片任务），执行任务时，runloop会被唤醒,一旦runloop状态改变，就会收到通知消息
//                print(weakSelf.TaskMarr.count)
                let task:runloopTask = weakSelf.TaskMarr.first!
                task()
                weakSelf.TaskMarr.removeFirst()
               
            }else{
                return;
            }
        }
    }
}
class ItemCell: UICollectionViewCell {
    
    @IBOutlet weak var backImg: UIImageView!
    override func awakeFromNib() {
        super.awakeFromNib()
    }
    
}
